/*
 * Copyright 2023, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */

#include <KernelExport.h>
#include <PCI.h>
#include <OS.h>
#include <graphic_driver.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>

#include "driver.h"
#include "device.h"

#define TRACE_DRIVER
#ifdef TRACE_DRIVER
#define TRACE(x...) dprintf(DRIVER_PREFIX ": " x)
#else
#define TRACE(x...) ;
#endif

#define ERROR(x...) dprintf(DRIVER_PREFIX ": " x)

// 全局变量
int32 api_version = B_CUR_DRIVER_API_VERSION;
static DeviceData *gDeviceData = NULL;
static pci_module_info *gPCI = NULL;

// 设备钩子函数
static device_hooks gDeviceHooks = {
    device_open,
    device_close,
    device_free,
    device_ioctl,
    device_read,
    device_write,
    NULL,
    NULL,
    NULL,
    NULL};

// 支持的设备列表
static struct
{
    uint16 vendor_id;
    uint16 device_id;
    const char *name;
} kSupportedDevices[] = {
    {VENDOR_ID_LOONGSON, DEVICE_ID_LS7A2000_GPU, "LS7A2000 GPU"},
    {0, 0, NULL}};

// 探测设备
static void
probe_devices()
{
    TRACE("probe_devices()\n");

    // 初始化设备计数
    gDeviceData->count = 0;

    // 遍历PCI设备
    pci_info info;
    for (int32 index = 0; gPCI->get_nth_pci_info(index, &info) == B_OK; index++)
    {
        // 检查是否是支持的设备
        for (int32 i = 0; kSupportedDevices[i].vendor_id != 0; i++)
        {
            if (info.vendor_id == kSupportedDevices[i].vendor_id && info.device_id == kSupportedDevices[i].device_id)
            {
                // 找到支持的设备
                TRACE("Found device: %s\n", kSupportedDevices[i].name);

                // 检查是否超过最大设备数
                if (gDeviceData->count >= MAX_LS7A2000_DEVICES)
                {
                    ERROR("Too many devices found!\n");
                    break;
                }

                // 初始化设备信息
                memset(&gDeviceData->di[gDeviceData->count], 0, sizeof(device_info));
                gDeviceData->di[gDeviceData->count].pcii = info;

                // 创建设备名称
                sprintf(gDeviceData->di[gDeviceData->count].name, DEVICE_FORMAT,
                        info.vendor_id, info.device_id,
                        info.bus, info.device, info.function);
                TRACE("Device name: %s\n", gDeviceData->di[gDeviceData->count].name);

                // 添加设备名称到列表
                gDeviceData->device_names[gDeviceData->count] =
                    strdup(gDeviceData->di[gDeviceData->count].name);

                // 增加设备计数
                gDeviceData->count++;
                break;
            }
        }
    }

    // 设置设备名称列表结束标记
    gDeviceData->device_names[gDeviceData->count] = NULL;

    TRACE("Found %ld devices\n", gDeviceData->count);
}

// 初始化硬件
status_t
init_hardware()
{
    TRACE("init_hardware()\n");

    // 获取PCI模块
    if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI) != B_OK)
    {
        ERROR("Failed to get PCI module\n");
        return B_ERROR;
    }

    // 检查是否有支持的设备
    pci_info info;
    bool found = false;

    for (int32 index = 0; gPCI->get_nth_pci_info(index, &info) == B_OK; index++)
    {
        for (int32 i = 0; kSupportedDevices[i].vendor_id != 0; i++)
        {
            if (info.vendor_id == kSupportedDevices[i].vendor_id && info.device_id == kSupportedDevices[i].device_id)
            {
                found = true;
                break;
            }
        }
        if (found)
            break;
    }

    // 释放PCI模块
    put_module(B_PCI_MODULE_NAME);

    return found ? B_OK : B_ERROR;
}

// 初始化驱动程序
status_t
init_driver()
{
    TRACE("init_driver()\n");

    // 获取PCI模块
    if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI) != B_OK)
    {
        ERROR("Failed to get PCI module\n");
        return B_ERROR;
    }

    // 分配设备数据结构
    gDeviceData = (DeviceData *)malloc(sizeof(DeviceData));
    if (gDeviceData == NULL)
    {
        ERROR("Failed to allocate device data\n");
        put_module(B_PCI_MODULE_NAME);
        return B_NO_MEMORY;
    }

    // 初始化设备数据
    memset(gDeviceData, 0, sizeof(DeviceData));

    // 初始化信号量
    status_t status = B_OK;
    status = benaphore_init(&gDeviceData->kernel, "ls7a2000 kernel");
    if (status != B_OK)
    {
        ERROR("Failed to init kernel benaphore\n");
        free(gDeviceData);
        put_module(B_PCI_MODULE_NAME);
        return status;
    }

    // 探测设备
    probe_devices();

    // 检查是否找到设备
    if (gDeviceData->count == 0)
    {
        ERROR("No devices found\n");
        benaphore_destroy(&gDeviceData->kernel);
        free(gDeviceData);
        put_module(B_PCI_MODULE_NAME);
        return B_ERROR;
    }

    return B_OK;
}

// 发布设备
const char **
publish_devices()
{
    TRACE("publish_devices()\n");
    return (const char **)gDeviceData->device_names;
}

// 查找设备
device_hooks *
find_device(const char *name)
{
    TRACE("find_device(%s)\n", name);

    // 遍历设备名称列表
    for (int32 i = 0; gDeviceData->device_names[i] != NULL; i++)
    {
        if (strcmp(name, gDeviceData->device_names[i]) == 0)
        {
            return &gDeviceHooks;
        }
    }

    return NULL;
}

// 卸载驱动程序
void uninit_driver()
{
    TRACE("uninit_driver()\n");

    // 释放设备名称
    for (int32 i = 0; i < gDeviceData->count; i++)
    {
        free(gDeviceData->device_names[i]);
    }

    // 销毁信号量
    benaphore_destroy(&gDeviceData->kernel);

    // 释放设备数据
    free(gDeviceData);

    // 释放PCI模块
    put_module(B_PCI_MODULE_NAME);
}